#include "mainwindow.hpp"
#include "qdbusviewer.h"
#include "ui_mainwindow.h"

#include <qmessagebox.h>
#include "dbustypedlg.hpp"
#include <QtDBus>
#include <qtreeview.h>
#include "devicedlg.hpp"
#include "propertydlg.hpp"

#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusMetaType>

#include <private/qdbusutil_p.h>

#include <qclipboard.h>
#include <qfiledialog.h>
#include <qscrollbar.h>
#include "dbuslog.hpp"

QMenu* MainWindow::tableHeaderMenu(QTableView *table)
{
    QMenu *menu = new QMenu();
    QHeaderView *header =table->horizontalHeader ();
    int count = header->count ();
    for(int i =0;i<count;i++) {

        QString title =  table->model ()->headerData (i,Qt::Horizontal,Qt::DisplayRole).toString ();
        QAction *Action = menu->addAction(title);
        Action->setCheckable (true);
        Action->setChecked (!header->isSectionHidden (i));
    }
    return menu;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),objectPathRegExp(QLatin1String("\\[ObjectPath: (.*)\\]"))
{
    ui->setupUi(this);
    ui->dockWidget_3->close ();
    fileToolBar = new QToolBar(this);
    fileToolBar->setWindowTitle ("File tool");
    deviceToolBar = new QToolBar(this);
    deviceToolBar->setWindowTitle ("Device tool");
    runToolBar = new QToolBar(this);
    runToolBar->setWindowTitle ("Run tool");
    editToolBar = new QToolBar(this);
    editToolBar->setWindowTitle ("Edit tool");
    this->removeToolBar(ui->mainToolBar);
    this->addToolBar(Qt::TopToolBarArea, fileToolBar);
    this->addToolBar(Qt::TopToolBarArea, deviceToolBar);
    this->addToolBar(Qt::TopToolBarArea, runToolBar);
    this->addToolBar(Qt::TopToolBarArea, editToolBar);


    fileToolBar->addAction(ui->actionExport);
    fileToolBar->addAction(ui->actionImport);

    deviceToolBar->addAction(ui->actionAddDevice);
    deviceToolBar->addAction(ui->actionDelDevice);

    runToolBar->addAction(ui->actionRun);
    runToolBar->addAction(ui->actionNext);
    runToolBar->addAction(ui->actionLoop);
    runToolBar->addAction(ui->actionStop);

    editToolBar->addAction(ui->actionMoveUp);
    editToolBar->addAction(ui->actionMoveDown);
    editToolBar->addAction(ui->actionAdd);
    editToolBar->addAction(ui->actionDel);
    editToolBar->addAction(ui->actionCopy);
    editToolBar->addAction(ui->actionPaste);

    ui->actionAddDevice->setIcon (QIcon(":/toolbar/images/toolbar/link_device.svg"));
    ui->actionDelDevice->setIcon (QIcon(":/toolbar/images/toolbar/unlink_device.svg"));
    ui->actionExport->setIcon (QIcon(":/toolbar/images/toolbar/Export.svg"));
    ui->actionImport->setIcon (QIcon(":/toolbar/images/toolbar/import.svg"));
    ui->actionMoveUp->setIcon (QIcon(":/toolbar/images/toolbar/up.svg"));
    ui->actionMoveDown->setIcon (QIcon(":/toolbar/images/toolbar/down.svg"));
    ui->actionAdd->setIcon (QIcon(":/toolbar/images/toolbar/add.svg"));
    ui->actionDel->setIcon (QIcon(":/toolbar/images/toolbar/delete.svg"));
    ui->actionCopy->setIcon (QIcon(":/toolbar/images/toolbar/copy.svg"));
    ui->actionPaste->setIcon (QIcon(":/toolbar/images/toolbar/paste.svg"));
    ui->actionRun->setIcon (QIcon(":/toolbar/images/toolbar/run.svg"));
    ui->actionNext->setIcon (QIcon(":/toolbar/images/toolbar/next.svg"));
    ui->actionStop->setIcon (QIcon(":/toolbar/images/toolbar/stop.svg"));
    ui->actionLoop->setIcon (QIcon(":/toolbar/images/toolbar/loop.svg"));

    ui->actionExit->setShortcut(QKeySequence::Quit);
    ui->actionExit->setMenuRole(QAction::QuitRole);



    QObject::connect(ui->actionExport, SIGNAL(triggered()), this, SLOT(on_actionExportClicked()));
    QObject::connect(ui->actionImport, SIGNAL(triggered()), this, SLOT(on_actionImportClicked()));

    QObject::connect(ui->actionAddDevice, SIGNAL(triggered()), this, SLOT(addDevice()));
    QObject::connect(ui->actionDelDevice, SIGNAL(triggered()), this, SLOT(delDevice()));

    QObject::connect(ui->actionRun, SIGNAL(triggered()), this, SLOT(on_actionRunClicked()));
    QObject::connect(ui->actionNext, SIGNAL(triggered()), this, SLOT(on_actionStepClicked()));
    QObject::connect(ui->actionLoop, SIGNAL(triggered()), this, SLOT(on_actionLoopClicked()));
    QObject::connect(ui->actionStop, SIGNAL(triggered()), this, SLOT(on_actionStopClicked()));

    QObject::connect(ui->actionMoveUp, SIGNAL(triggered()), this, SLOT(on_actionUpClicked()));
    QObject::connect(ui->actionMoveDown, SIGNAL(triggered()), this, SLOT(on_actionDownClicked()));
    QObject::connect(ui->actionAdd, SIGNAL(triggered()), this, SLOT(on_actionAddClicked()));
    QObject::connect(ui->actionDel, SIGNAL(triggered()), this, SLOT(on_actionDelClicked()));
    QObject::connect(ui->actionCopy, SIGNAL(triggered()), this, SLOT(on_actionCopyClicked()));
    QObject::connect(ui->actionPaste, SIGNAL(triggered()), this, SLOT(on_actionPasteClicked()));










    ui->DbusObjectView->horizontalHeader()->setContextMenuPolicy (Qt::CustomContextMenu);
    connect (ui->DbusObjectView->horizontalHeader(),&QHeaderView::customContextMenuRequested,
             this,&MainWindow::on_customContextMenuRequested);
    ui->serviceFilterLine->setPlaceholderText(tr("Search..."));
    dbusObjModel = new DbusObjModel(this);
    dbusObjProxyModel = new QSortFilterProxyModel(this);
    dbusObjProxyModel->setSourceModel(dbusObjModel);
    dbusObjProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    ui->DbusObjectView->setModel(dbusObjProxyModel);
    ui->DbusObjectView->setSortingEnabled(true);
    ui->DbusObjectView->sortByColumn(0, Qt::AscendingOrder);

    connect(ui->serviceFilterLine, SIGNAL(textChanged(QString)), dbusObjProxyModel, SLOT(setFilterFixedString(QString)));

    dbusmethodmodel = new DbusMethodModel(this);
    dbusmethodProxyModel = new QSortFilterProxyModel(this);


    dbusmethodProxyModel->setSourceModel(dbusmethodmodel);
    dbusmethodProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);

    ui->leMethodfliter->setPlaceholderText(tr("Search..."));
    connect(ui->leMethodfliter, SIGNAL(textChanged(QString)), dbusmethodProxyModel, SLOT(setFilterFixedString(QString)));
    ui->tvMethodView->setModel(dbusmethodProxyModel);
    ui->tvMethodView->setSortingEnabled(true);
    ui->tvMethodView->sortByColumn(0, Qt::AscendingOrder);
    ui->tvMethodView->verticalHeader ()->setHidden (true);

    setupDragDrop(ui->tvMethodView);
    //    connect(ui->DbusObjectView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
    //            this, [](QModelIndex){});


    m_testModel = new DragDropModel(this);
    ui->tvTest->setModel (m_testModel);
    ui->tvTest->setDragEnabled(true);
    ui->tvTest->setDragDropMode(QAbstractItemView::InternalMove);


    ui->tvTest->setSelectionMode(QAbstractItemView::ExtendedSelection);
    ui->tvTest->setDragEnabled(true);
    ui->tvTest->setAcceptDrops(true);
    ui->tvTest->setDropIndicatorShown(true);


    m_signalModel  = new DbusSignalModel(this);
    ui->tvSignal->setModel (m_signalModel);
    connect (m_signalModel,&DbusSignalModel::signalCall,this,&MainWindow::signalMessage);



    ui->tvSignal->horizontalHeader()->setContextMenuPolicy (Qt::CustomContextMenu);
    ui->tvTest->horizontalHeader()->setContextMenuPolicy (Qt::CustomContextMenu);
    connect (ui->tvTest->horizontalHeader(),&QHeaderView::customContextMenuRequested,
             this,&MainWindow::on_customContextMenuRequested1);
    connect (ui->tvSignal->horizontalHeader(),&QHeaderView::customContextMenuRequested,
             this,&MainWindow::on_customContextMenuRequested2);

    m_signalView_customContextMenu = tableHeaderMenu(ui->tvSignal);
    m_testView_customContextMenu = tableHeaderMenu(ui->tvTest);
    connect (m_signalView_customContextMenu,&QMenu::triggered,this,&MainWindow::onCustomContextTriggered2);
    connect (m_testView_customContextMenu,&QMenu::triggered,this,&MainWindow::onCustomContextTriggered1);


    connect(ui->serviceFilterLine, &QLineEdit::textChanged, [=](QString str){

        dbusObjProxyModel->setFilterFixedString (str);
    });
    connect(ui->DbusObjectView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(objectSelectionChanged(QItemSelection)));
    connect(ui->tvTest->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(testSelectionChanged(QItemSelection)));
    connect(ui->tvMethodView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(methodSelectionChanged(QItemSelection)));

    connect(ui->tvMethodView, SIGNAL(activated(QModelIndex)), this, SLOT(activate(QModelIndex)));

    restoreSettings();
    ui->DbusObjectView->resizeColumnsToContents ();
    ui->tvMethodView->resizeColumnsToContents ();

    m_DbusObjectView_customContextMenu = tableHeaderMenu(ui->DbusObjectView);
    connect (m_DbusObjectView_customContextMenu,&QMenu::triggered,this,&MainWindow::onCustomContextTriggered);



    connect (&m_dbusCaller,&DbusCaller::onStart,this,&MainWindow::onDbusCallStart);
    connect (&m_dbusCaller,&DbusCaller::onFinish,this,&MainWindow::onDbusCallFinish);
    connect (&m_dbusCaller,&DbusCaller::onItemStart,this,&MainWindow::onDbusCallItemStart);
    connect (&m_dbusCaller,&DbusCaller::onItemFinish1,this,&MainWindow::onDbusCallItemFinish);
    connect (&m_dbusCaller,&DbusCaller::onResetResult,this,&MainWindow::onDbusResetResult);



    enbleAction();
    ui->tvMethodView->horizontalScrollBar ()->setDisabled (true);
    ui->tvMethodView->horizontalHeader ()->setSectionResizeMode (QHeaderView::Stretch);
}

void MainWindow::enbleAction()
{

    bool bEnable = false;
    if(m_dbusCaller.isRunning ())
    {
        ui->actionStop->setEnabled (true);
        ui->actionDelDevice->setEnabled (false);
        ui->actionExport->setEnabled (false);
        ui->actionRun->setEnabled (false);
        ui->actionLoop->setEnabled (false);
        ui->actionDelDevice->setEnabled (false);
        ui->actionDel->setEnabled (false);
        ui->actionCopy->setEnabled (false);
        ui->actionPaste->setEnabled (false);
        ui->actionMoveUp->setEnabled (false);
        ui->actionMoveDown->setEnabled (false);
        ui->actionAdd->setEnabled (false);
    }else
    {
        ui->actionStop->setEnabled (false);
        ui->actionImport->setEnabled (true);
        if(m_testModel->rowCount (QModelIndex())>0)
        {
            ui->actionExport->setEnabled (true);
            ui->actionRun->setEnabled (true);
            ui->actionLoop->setEnabled (true);
        }else
        {
            ui->actionExport->setEnabled (false);
            ui->actionRun->setEnabled (false);
            ui->actionLoop->setEnabled (false);
        }

        if(ui->DbusObjectView->selectionModel ()->currentIndex ().isValid ())
        {
            ui->actionDelDevice->setEnabled (true);
        }else
        {
            ui->actionDelDevice->setEnabled (false);
        }

        ui->actionAddDevice->setEnabled (true);
        if(ui->tvTest->selectionModel ()->selectedRows ().count ()>0)
        {
            ui->actionDel->setEnabled (true);
            ui->actionCopy->setEnabled (true);
            ui->actionMoveUp->setEnabled (true);
            ui->actionMoveDown->setEnabled (true);
            ui->actionNext->setEnabled (true);
        }else
        {
            ui->actionDel->setEnabled (false);
            ui->actionCopy->setEnabled (false);
            ui->actionMoveUp->setEnabled (false);
            ui->actionMoveDown->setEnabled (false);
            ui->actionNext->setEnabled (false);
        }


        QClipboard *clipboard = QGuiApplication::clipboard();
        const QMimeData* mimeData = clipboard->mimeData ();
        if(mimeData->hasImage ())
        {
            QVariant v = mimeData->imageData ();
            if(v.userType () == qMetaTypeId<QList<DbusTestCopyItem>>())
            {
                bEnable = true;
            }
        }
        ui->actionPaste->setEnabled (bEnable);
        if(ui->tvMethodView->selectionModel ()->currentIndex ().isValid ())
        {
            ui->actionAdd->setEnabled (true);
        }else
        {
            ui->actionAdd->setEnabled (false);
        }
    }
}


void MainWindow::setupDragDrop(QTableView *tableView) {
    tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    tableView->setDragEnabled(true);
    tableView->viewport()->setAcceptDrops(true);

    //    // 当用户开始拖动时，会触发dragMoveEvent
    //    connect(tableView, &QTableView::dragMoveEvent, [tableView](QDragMoveEvent *event) {
    //        // 如果拖动的是行，则接受拖动
    //        if (tableView->selectionModel()->hasSelection()) {
    //            event->acceptProposedAction();
    //        }
    //    });

    //    // 当拖动操作完成时，处理数据
    //    connect(tableView, &QTableView::dropEvent, [tableView](QDropEvent *event)
    //        const QModelIndex index = tableView->indexAt(event->pos());
    //        if (index.isValid()) {
    //            // 处理拖动的数据
    //            // ...
    //        }
    //    });
}
MainWindow::~MainWindow()
{
    saveState();

    delete dbusObjModel;
    delete dbusObjProxyModel;
    delete dbusmethodmodel;
    delete dbusmethodProxyModel;
    delete m_testModel;
    delete m_DbusObjectView_customContextMenu;

    delete ui;
}
void MainWindow::about()
{
    QMessageBox box(this);

    box.setText(QString::fromLatin1("<center><img src=\":/images/tm.png\">"
                                    "<h3>%1</h3>"
                                    "<p>Version %2</p></center>"
                                    "<p>Copyright (C) %3 CYG Ltd.</p>")
                .arg(tr("TM3 Debug Tools"), QLatin1String(QT_VERSION_STR), QStringLiteral("2024")));
    box.setWindowTitle(tr("TM3 Debug Tools"));
    box.exec();
}
void MainWindow::activate(const QModelIndex &item)
{
    if (!item.isValid())
        return;
    const QModelIndex indexs = dbusmethodProxyModel->mapToSource(item);
    DbusMethodItem *aitem = dbusmethodmodel->getItem (indexs);
    QList<DVariant> Args;
    DbusTestModelItem *witem = new DbusTestModelItem(aitem->m_data,Args);
    witem->setSkip (false);
    if(witem->m_data.argTypes.count ()>0
            || aitem->m_data.type == SignalItem
            || aitem->m_data.type == PropertyItemReadwrite
            || aitem->m_data.type == PropertyItemWrite
            )
    {
        PropertyDlg dlg(witem->m_data,this);
        if(dlg.exec () == QDialog::Rejected)
        {
            return;
        }

        witem->dbusArgs = dlg.Args();
        if(!dlg.m_toSeq && witem->m_data.type == SignalItem)
        {
            m_signalModel->append (witem);
            return;
        }
    }
    m_testModel->append (witem);
    ui->tvTest->resizeColumnsToContents ();
    enbleAction();
}
void MainWindow::addDevice()
{
    DeviceDlg dlg(this);
    if(dlg.exec ())
    {
        dbusObjModel->append (dlg.bus ().name (),dlg.getCurrentService(),dlg.getCurrentPath (),dlg.getCurrentInterface ());
        ui->DbusObjectView->resizeColumnsToContents ();
    }
    return;
}
void MainWindow::delDevice()
{
    QModelIndexList selected = ui->DbusObjectView->selectionModel ()->selectedRows ();
    std::sort(selected.begin (),selected.end (),[](QModelIndex a,QModelIndex b){ return a.row ()>b.row ();});
    if (!selected.isEmpty()) {
        for (const QModelIndex &index : selected) {
            dbusObjModel->remove(index.row(), index.parent());
        }
    }
//    ui->DbusObjectView->resizeColumnsToContents ();
}

void MainWindow::on_customContextMenuRequested1(const QPoint &pos)
{
    QHeaderView *header =ui->tvTest->horizontalHeader ();
    int count = header->count ();
    for(int i =0;i<count;i++) {
        m_testView_customContextMenu->actions ().at (i)->setChecked (!header->isSectionHidden (i));
    }
    m_testView_customContextMenu->exec(mapToGlobal(pos));
}
void MainWindow::on_customContextMenuRequested2(const QPoint &pos)
{
    QHeaderView *header =ui->tvSignal->horizontalHeader ();
    int count = header->count ();
    for(int i =0;i<count;i++) {
        m_signalView_customContextMenu->actions ().at (i)->setChecked (!header->isSectionHidden (i));
    }
    m_signalView_customContextMenu->exec(mapToGlobal(pos));
}
void MainWindow::on_customContextMenuRequested(const QPoint &pos)
{
    m_DbusObjectView_customContextMenu->exec(mapToGlobal(pos));
}

void MainWindow::onCustomContextTriggered(QAction *action)
{
    QHeaderView *header =ui->DbusObjectView->horizontalHeader ();
    int count = header->count ();
    bool isAllHidden = true;
    int index = -1;
    for(int i =0;i<count;i++) {
        QString title =  dbusObjModel->headerData (i,Qt::Horizontal,Qt::DisplayRole).toString ();
        if(action->text () == title)
        {
            index = i;
        }else if(!header->isSectionHidden (i))
        {
            isAllHidden = false;
        }
    }
    if(!isAllHidden)
    {
        header->setSectionHidden (index,!header->isSectionHidden (index));
    }

}
void MainWindow::onCustomContextTriggered1(QAction *action)
{
    QHeaderView *header =ui->tvTest->horizontalHeader ();
    int count = header->count ();
    bool isAllHidden = true;
    int index = -1;
    for(int i =0;i<count;i++) {
        QString title =  ui->tvTest->model ()->headerData (i,Qt::Horizontal,Qt::DisplayRole).toString ();
        if(action->text () == title)
        {
            index = i;
        }else if(!header->isSectionHidden (i))
        {
            isAllHidden = false;
        }
    }
    if(!isAllHidden)
    {
        header->setSectionHidden (index,!header->isSectionHidden (index));
    }

}
void MainWindow::onCustomContextTriggered2(QAction *action)
{
    QHeaderView *header =ui->tvSignal->horizontalHeader ();
    int count = header->count ();
    bool isAllHidden = true;
    int index = -1;
    for(int i =0;i<count;i++) {
        QString title =  ui->tvSignal->model ()->headerData (i,Qt::Horizontal,Qt::DisplayRole).toString ();
        if(action->text () == title)
        {
            index = i;
        }else if(!header->isSectionHidden (i))
        {
            isAllHidden = false;
        }
    }
    if(!isAllHidden)
    {
        header->setSectionHidden (index,!header->isSectionHidden (index));
    }

}

void MainWindow::objectSelectionChanged(const QItemSelection &index)
{
    enbleAction();
    if(dbusObjProxyModel)
    {
        const QModelIndex indexs = dbusObjProxyModel->mapToSource(index.indexes ().first ());
        BusSignatureEx data = dbusObjModel->getItemData (indexs);
        if(data.type ==  LocalMethod)
        {
dbusmethodmodel->refreshlocalMethod ();
        }else
        {
            dbusmethodmodel->refresh (data.mBus,
                                      data.mService,
                                      data.mPath,
                                      data.mInterface);
        }
        ui->tvMethodView->resizeColumnsToContents ();
    }

}

void MainWindow::testSelectionChanged(const QItemSelection &index)
{
    enbleAction();
}

void MainWindow::methodSelectionChanged(const QItemSelection &index)
{
    enbleAction();
}


#define Setting_MainWindow_main "MainWindow_main"
#define Setting_MainWindow_DbusObjectView_Value "MainWindow_DbusObjectView_Value"
#define Setting_MainWindow_DbusObjectView_table_list "MainWindow_DbusObjectView_table_list"
#define Setting_MainWindow_DbusObjectView_table_currentIndex "MainWindow_DbusObjectView_table_currentIndex"
#define Setting_MainWindow_DbusObjectView_table_ColumnHidden "DbusObjectView_table_ColumnHidden"
#define Setting_MainWindow_Test_table_ColumnHidden "TestView_table_ColumnHidden"
#define Setting_MainWindow_DbusObjectView_table_list "MainWindow_MethodView_table_list"
#define Setting_MainWindow_TestView_table_list "MainWindow_test_table_list"
#define Setting_MainWindow_Signal_table_list "MainWindow_Signal_table_list"
#define Setting_MainWindow_runlog "MainWindow_test_run_log"
#define Setting_MainWindow_signallog "MainWindow_test_signal_log"

void MainWindow::saveState() const
{
#ifdef Q_OS_MAC
    QSettings settings;
#else
    QSettings settings("TestManager_Dbg_tools.ini",QSettings::IniFormat);
#endif
    settings.setValue(Setting_MainWindow_main, saveGeometry());
    settings.beginGroup(Setting_MainWindow_DbusObjectView_Value);

    settings.setValue(Setting_MainWindow_runlog,m_logfile);
    settings.setValue(Setting_MainWindow_signallog,m_signalfile);

    QByteArray context = dbusObjModel->toContext ();
    settings.setValue(Setting_MainWindow_DbusObjectView_table_list,context);
    settings.setValue(Setting_MainWindow_DbusObjectView_table_currentIndex,ui->DbusObjectView->currentIndex ().row ());
    QString test = m_testModel->exportXML ();
    settings.setValue(Setting_MainWindow_TestView_table_list,test);
    test = m_signalModel->exportXML ();
    settings.setValue(Setting_MainWindow_Signal_table_list,test);

    int hide = 0;
    for(int i=0;i<ui->DbusObjectView->horizontalHeader()->count ();i++)
    {
        if(ui->DbusObjectView->isColumnHidden (i))
        {
            hide += 1<<i;
        }
    }
    settings.setValue(Setting_MainWindow_DbusObjectView_table_ColumnHidden,hide);
    hide = 0;
    for(int i=0;i<ui->tvTest->horizontalHeader()->count ();i++)
    {
        if(ui->tvTest->isColumnHidden (i))
        {
            hide += 1<<i;
        }
    }
    settings.setValue(Setting_MainWindow_Test_table_ColumnHidden,hide);
    settings.endGroup();
}

void MainWindow::restoreSettings()
{
#ifdef Q_OS_MAC
    QSettings settings;
#else
    QSettings settings("TestManager_Dbg_tools.ini",QSettings::IniFormat);
#endif
    if(restoreGeometry(settings.value(Setting_MainWindow_main).toByteArray()))
    {
        settings.beginGroup(Setting_MainWindow_DbusObjectView_Value);

        m_logfile = settings.value(Setting_MainWindow_runlog).toString ();
        connect (&runLog(m_logfile),&DbusLog::logNameChange,this,&MainWindow::noRunlogNameChange);
        m_signalfile = settings.value(Setting_MainWindow_signallog).toString ();
        connect (&signalLog(m_signalfile),&DbusLog::logNameChange,this,&MainWindow::noSignallogNameChange);


        QString context = settings.value(Setting_MainWindow_DbusObjectView_table_list).toString ();
        dbusObjModel->refresh (context);
        int currentrow = settings.value(Setting_MainWindow_DbusObjectView_table_currentIndex).toInt ();
        ui->DbusObjectView->setCurrentIndex (dbusObjProxyModel->index (currentrow,0));

        QString test = settings.value(Setting_MainWindow_TestView_table_list).toString ();
        m_testModel->importXML (test);

        test = settings.value (Setting_MainWindow_Signal_table_list).toString ();
        m_signalModel->importXML (test);

        int hide = settings.value(Setting_MainWindow_DbusObjectView_table_ColumnHidden).toInt ();
        if(hide<0)
        {
            hide = 2+4+8;
        }
        for(int i=0;i<ui->DbusObjectView->horizontalHeader()->count ();i++)
        {
            if(hide&1<<i)
            {
                ui->DbusObjectView->setColumnHidden(i,true);
            }else
            {
                ui->DbusObjectView->setColumnHidden(i,false);
            }
        }


        hide = settings.value(Setting_MainWindow_Test_table_ColumnHidden).toInt ();
        if(hide<0)
        {
            hide = 1+2+4+8;
        }
        for(int i=0;i<ui->tvTest->horizontalHeader()->count ();i++)
        {
            if(hide&1<<i)
            {
                ui->tvTest->setColumnHidden(i,true);
            }else
            {
                ui->tvTest->setColumnHidden(i,false);
            }
        }
        settings.endGroup();
    }
}
void MainWindow::on_actionUpClicked()
{
    QModelIndexList selected = ui->tvTest->selectionModel ()->selectedRows ();
    std::sort(selected.begin (),selected.end (),[](QModelIndex a,QModelIndex b){ return a.row ()<b.row ();});
    if (!selected.isEmpty()) {
        int startRow = selected.at(0).row();
        if(startRow == 0)
        {
            return;
        }
        for (const QModelIndex &index : selected) {
            m_testModel->moveRow (index.parent(),index.row(), index.parent(),index.row()-1);
        }
    }
}

void MainWindow::on_actionDownClicked()
{
    QModelIndexList selected = ui->tvTest->selectionModel ()->selectedRows ();
    std::sort(selected.begin (),selected.end (),[](QModelIndex a,QModelIndex b){ return a.row ()>b.row ();});
    if (!selected.isEmpty()) {
        int startRow = selected.at(0).row()+1;
        int count = m_testModel->rowCount (selected.first ().parent ());
        if(startRow>=count)
        {
            return;
        }
        for (const QModelIndex &index : selected) {
            m_testModel->moveRow (index.parent(),index.row(), index.parent(),index.row()+1);
        }
    }
}

void MainWindow::on_actionDelClicked()
{
    QModelIndexList selected = ui->tvTest->selectionModel ()->selectedRows ();
    std::sort(selected.begin (),selected.end (),[](QModelIndex a,QModelIndex b){ return a.row ()>b.row ();});
    if (!selected.isEmpty()) {
        int startRow = selected.at(0).row();
        for (const QModelIndex &index : selected) {
            m_testModel->removeRow(index.row(), index.parent());
        }
    }
}

void MainWindow::on_actionRunClicked()
{
    QVector<DbusTestModelItem *> list = m_testModel->getItemList ();
    m_dbusCaller.start (list);
}

void MainWindow::on_actionExitClicked()
{
    QTimer::singleShot(1 * 1000, qApp, SLOT(quit()));
}

void MainWindow::noRunlogNameChange(const QString &path, const QString &prefix, const QString &filename)
{
    m_logfile = filename;
    QSettings settings;
    settings.setValue(Setting_MainWindow_main, saveGeometry());
    settings.beginGroup(Setting_MainWindow_DbusObjectView_Value);
    settings.setValue (Setting_MainWindow_runlog,m_logfile);
    settings.endGroup ();
}

void MainWindow::noSignallogNameChange(const QString &path, const QString &prefix, const QString &filename)
{
    m_signalfile = filename;
    QSettings settings;
    settings.setValue(Setting_MainWindow_main, saveGeometry());
    settings.beginGroup(Setting_MainWindow_DbusObjectView_Value);
    settings.setValue (Setting_MainWindow_signallog,m_signalfile);
    settings.endGroup ();
}
void MainWindow::on_actionStepClicked()
{
    QModelIndex index = ui->tvTest->selectionModel ()->currentIndex ();
    DbusTestModelItem * item = m_testModel->getItem (index);
    m_dbusCaller.start (item,index.row ());
}

void MainWindow::on_actionLoopClicked()
{
    QVector<DbusTestModelItem *> list = m_testModel->getItemList ();
    m_dbusCaller.loop (list,-1);
}

void MainWindow::on_actionStopClicked()
{
    m_dbusCaller.stop ();
}
void MainWindow::onDbusCallItemStart(DbusTestModelItem *item,int row)
{
    item->m_starttime = QDateTime::currentMSecsSinceEpoch ();
    runLog()<<"run item start:"<<QDateTime::currentDateTime ()<<endl;
    runLog()<<"bus:"<<item->m_data.mBus<<endl;
    runLog()<<"Service:"<<item->m_data.mService<<endl;
    runLog()<<"path:"<<item->m_data.mPath<<endl;
    runLog()<<"Interface:"<<item->m_data.mInterface<<endl;
    runLog()<<"category:";
    switch (item->m_data.type) {
    case MethodItem:
        runLog()<<"Method"<<endl;
        break;
    case SignalItem:
        runLog()<<"Signal"<<endl;
        break;
    case PropertyItemReadwrite:
    case PropertyItemRead:
    case PropertyItemWrite:
        if(item->dbusArgs.count ()>0)
        {
            runLog()<<"SetProperty"<<endl;
        }else
        {
            runLog()<<"GetProperty"<<endl;
        }
        break;
    default:
        runLog()<<endl;
        break;
    }
    runLog()<<"name:"<<item->m_data.mName<<endl;
    runLog()<<"args:"<<endl;
    for(int i=0;i<item->dbusArgs.count ();i++)
    {
        if(item->m_data.argNames.count ()>i)
        {
            runLog()<<item->m_data.argNames.at (i);
            runLog()<< " = ";
        }else
        {
            runLog()<<"arg"<<i;
            runLog()<< " = ";
        }
        runLog()<<item->dbusArgs.at (i)<<endl;
    }
    runLog()<<endl;
    item->setResult("runing");
    QModelIndexList indexs = m_testModel->getResultIndex (row);
    for(QModelIndex index : indexs)
    {
        ui->tvTest->update(index);
    }
}

void MainWindow::onDbusCallItemFinish(DbusTestModelItem *item,int row,int loops, QVariant ret)
{
    bool bfrist = true;
    runLog()<<"run item finish:"<<QDateTime::currentDateTime ()<<endl;
    item->m_finshtime = QDateTime::currentMSecsSinceEpoch ();
    if(ret.userType()== qMetaTypeId<QDBusMessage>())
    {
        QDBusMessage msg = ret.value<QDBusMessage>();
        if(msg.type () == QDBusMessage::ErrorMessage)
        {
            QString strErr = msg.errorMessage ();
            strErr = strErr.replace ("\r","\\r");
            strErr = strErr.replace ("\n","\\n");
            runLog()<<"error:"<<strErr<<endl;
            runLog()<<endl;
            QDBusError dbusErr(msg);
            item->m_error = dbusErr.type ();
            item->m_errMsg = strErr;
            //        item->m_result = "";
        }else
        {
            item->m_error = 0;
            QList<QVariant> args = msg.arguments();
            QString out = QLatin1String("");
            //        item->m_result = "";
            bfrist = true;
            if(args.count () == 0)
            {
                runLog()<<"returns:void"<<endl;
            }else
            {
                runLog()<<"returns:"<<endl;
            }
            for (const QVariant &arg : qAsConst(args)) {
                if(bfrist)
                {
                    runLog()<<arg;
                    bfrist = false;

                }else
                {
                    runLog()<<","<<arg;
                }
            }
            item->setResult(QString(runLog().data ()));
            runLog()<<endl;
            runLog()<<endl;
        }
    }else
    {
        item->setResult(ret.toString ());
    }
    QModelIndexList indexs = m_testModel->getResultIndex (row);
    for(QModelIndex index : indexs)
    {
        ui->tvTest->update(index);
    }
}

void MainWindow::onDbusResetResult(int row)
{
    if(row < 0)
    {
        int rowCount = m_testModel->rowCount (QModelIndex());
        for(int i=0;i<rowCount;i++)
        {
            QModelIndexList indexs = m_testModel->getResultIndex (i);
            for(QModelIndex index : indexs)
            {
                if(index.isValid ())
                {
                ui->tvTest->update(index);
                }
            }
        }
    }else
    {
        QModelIndexList indexs = m_testModel->getResultIndex (row);
        for(QModelIndex index : indexs)
        {
            if(index.isValid ())
            {
            ui->tvTest->update(index);
            }
        }
    }
}

void MainWindow::onDbusCallStart()
{
    runLog()<<"start run:"<<QDateTime::currentDateTime ()<<endl;
    runLog()<<endl;
    enbleAction();
}
void MainWindow::onDbusCallFinish()
{
   runLog()<<"finish:"<<QDateTime::currentDateTime ()<<endl;
   runLog()<<endl;
   enbleAction();
}
void MainWindow::signalMessage(DbusTestModelItem *item, const QDBusMessage &msg)
{
    signalLog()<<"Singal Call:"<<QDateTime::currentDateTime ()<<endl;
    signalLog()<<"bus:"<<item->m_data.mBus<<endl;
    signalLog()<<"Service:"<<item->m_data.mService<<endl;
    signalLog()<<"path:"<<item->m_data.mPath<<endl;
    signalLog()<<"Interface:"<<item->m_data.mInterface<<endl;
    bool bfrist = true;
    QList<QVariant> args = msg.arguments();
    QString out = QLatin1String("");
    item->m_starttime = item->m_finshtime = 0;
    signalLog()<<"args:"<<endl;
    for (int i=0;i<args.count ();i++)
    {
        if(i>0)
        {
            signalLog()<<",";
        }
        if(item->m_data.argNames.count ()>i)
        {
            signalLog()<<item->m_data.argNames.at (i)<< " = ";
        }else
        {
            signalLog()<<"arg"<<i<< " = ";
        }
        signalLog()<<args.at (i);
    }
    item->setResult(QString(signalLog().data ()));
    item->m_starttime = item->m_finshtime = QDateTime::currentMSecsSinceEpoch ();
    signalLog()<<endl;
    signalLog()<<endl;
    QModelIndexList indexs = m_signalModel->getResultIndex (item);
    for(QModelIndex index : indexs)
    {
        ui->tvSignal->update(index);
    }
}
void MainWindow::dumpMessage(const QDBusMessage &message)
{
    QList<QVariant> args = message.arguments();
    QString out = QLatin1String("Received ");

    switch (message.type()) {
    case QDBusMessage::SignalMessage:
        out += QLatin1String("signal ");
        break;
    case QDBusMessage::ErrorMessage:
        out += QLatin1String("error message ");
        break;
    case QDBusMessage::ReplyMessage:
        out += QLatin1String("reply ");
        break;
    default:
        out += QLatin1String("message ");
        break;
    }

    out += QLatin1String("from ");
    out += message.service();
    if (!message.path().isEmpty())
        out += QLatin1String(", path ") + message.path();
    if (!message.interface().isEmpty())
        out += QLatin1String(", interface <i>") + message.interface() + QLatin1String("</i>");
    if (!message.member().isEmpty())
        out += QLatin1String(", member ") + message.member();
    out += QLatin1String("<br>");
    if (args.isEmpty()) {
        out += QLatin1String("&nbsp;&nbsp;(no arguments)");
    } else {
        out += QLatin1String("&nbsp;&nbsp;Arguments: ");
        for (const QVariant &arg : qAsConst(args)) {
            QString str = QDBusUtil::argumentToString(arg).toHtmlEscaped();
            // turn object paths into clickable links
            str.replace(objectPathRegExp, QLatin1String("[ObjectPath: <a href=\"qdbus://bus\\1\">\\1</a>]"));
            // convert new lines from command to proper HTML line breaks
            str.replace(QStringLiteral("\n"), QStringLiteral("<br/>"));
            out += str;
            out += QLatin1String(", ");
        }
        out.chop(2);
    }
    ui->log->appendHtml(out);
}


void MainWindow::on_actionCopyClicked()
{
    QClipboard *clipboard = QGuiApplication::clipboard();
    QModelIndexList selected = ui->tvTest->selectionModel ()->selectedRows ();
    if (!selected.isEmpty()) {
        QMimeData* mimeData = new QMimeData;
        QList<DbusTestCopyItem> list;
        std::sort(selected.begin (),selected.end (),[](QModelIndex a,QModelIndex b){ return a.row ()<b.row ();});
        foreach (auto var, selected) {
            DbusTestModelItem *item = m_testModel->getItem (var);
            DbusTestCopyItem itemnew;
            itemnew.parent = item->parent;
            itemnew.m_data = item->m_data;
            itemnew.dbusArgs = item->dbusArgs;
            itemnew.m_skip = item->m_skip;
            list<<itemnew;
        }
        mimeData->setImageData (QVariant::fromValue(list));
        clipboard->setMimeData (mimeData);
        enbleAction();
    }
}
void MainWindow::on_actionPasteClicked()
{
    QClipboard *clipboard = QGuiApplication::clipboard();
    const QMimeData* mimeData = clipboard->mimeData ();
    if(mimeData->hasImage ())
    {
        QVariant v = mimeData->imageData ();
        if(v.userType () == qMetaTypeId<QList<DbusTestCopyItem>>())
        {
            clipboard->clear ();
            QList<DbusTestCopyItem> list = v.value<QList<DbusTestCopyItem>>();
            QModelIndex Index = ui->tvTest->selectionModel ()->currentIndex ();
            int position = Index.row ()+1;
            foreach (auto var, list) {
                DbusTestModelItem *item = new DbusTestModelItem(var.m_data,var.dbusArgs,var.parent);
                item->setSkip (var.m_skip);
                m_testModel->insertItem(position,item);
                position++;
            }

        }
    }
    enbleAction();

}
void MainWindow::on_actionExportClicked()
{
    QString strPath = qApp->applicationDirPath ();
    QDir dir(strPath);
    if(strPath.endsWith ("Contents/MacOS"))
    {
        dir.cdUp ();
        dir.cdUp ();
        dir.cdUp ();
    }
    strPath = dir.absolutePath ();
    QString filePath = QFileDialog::getSaveFileName(this,"Save",strPath,QString::fromLocal8Bit("*.xml"));
    if("" != filePath)
    {
        QFile file(filePath);
        if(file.open (QFile::WriteOnly))
        {
            QString str = m_testModel->exportXML();
            file.write (str.toLatin1 ());
            file.close ();
        }
    }
    enbleAction();
}

void MainWindow::on_actionImportClicked()
{
    QString strPath = qApp->applicationDirPath ();
    QDir dir(strPath);
    if(strPath.endsWith ("Contents/MacOS"))
    {
        dir.cdUp ();
        dir.cdUp ();
        dir.cdUp ();
    }
    strPath = dir.absolutePath ();
    QString filePath = QFileDialog::getOpenFileName (this,"Import",strPath,QString::fromLocal8Bit("*.xml"));
    if("" != filePath)
    {
        QFile file(filePath);
        if(file.open (QFile::ReadOnly))
        {
            QByteArray strArr = file.readAll ();
            file.close ();
            QString str = QString::fromLatin1 (strArr);
            m_testModel->importXML (str);

        }
    }
    enbleAction();
}

void MainWindow::on_tvTest_activated(const QModelIndex &index)
{
    if (!index.isValid())
        return;
    DbusTestModelItem *witem = m_testModel->getItem (index);
    if(!witem)
        return;
    if(witem->m_data.argTypes.count ()>0
            || witem->m_data.type == PropertyItemReadwrite
            || witem->m_data.type == PropertyItemWrite
            || witem->m_data.type == SignalItem
            )
    {
        PropertyDlg dlg(witem->m_data,witem->dbusArgs,this);
        if(dlg.exec () == QDialog::Rejected)
        {
            return;
        }
        witem->dbusArgs = dlg.Args();
        ui->tvTest->resizeColumnsToContents ();
    }
    //    m_testModel->append (witem);

}
void MainWindow::on_actionAddClicked()
{
    QModelIndex selected = ui->tvMethodView->selectionModel ()->currentIndex ();
    activate(selected);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if(m_dbusCaller.isRunning ())
    {
        QMessageBox::warning(this, QString::fromLocal8Bit("exit"), QString::fromLocal8Bit("the sequces is runing,exit  not allowed"), QMessageBox::Ok);
        event->ignore();

    }else
    {
        event->accept();
    }
}
